#include "utils.h"

void convertUYVYtoNV12(char *pSrcImage, char *pDstImage, int width, int height)
{

    char *uyvy_content = pSrcImage;
    char *nv12_y_ptr = pDstImage;
    char *nv12_uv_ptr = pDstImage + width * height;

    size_t pixels_in_a_row = width * 2;

    int lines = 0;
    for (int i = 0; i < width * height * 2; i += 4)
    {
        // copy y channel
        *nv12_y_ptr++ = uyvy_content[i + 1];
        *nv12_y_ptr++ = uyvy_content[i + 3];
        if (0 == i % pixels_in_a_row)
        {
            ++lines;
        }
        if (lines % 2 == 0)
        { // extract the UV value of even rows
            // copy uv channel
            *nv12_uv_ptr++ = uyvy_content[i];
            *nv12_uv_ptr++ = uyvy_content[i + 2];
        }
    }
    LOG_I("convert success");
}

void convertUYVYtoNV21(char *pSrcImage, char *pDstImage, int width, int height)
{
    char *uyvy_content = pSrcImage;
    char *nv12_y_ptr = pDstImage;
    char *nv12_uv_ptr = pDstImage + width * height;

    int pixels_in_a_row = width * 2;

    int lines = 0;
    for (int i = 0; i < width * height * 2; i += 4)
    {
        // copy y channel
        *nv12_y_ptr++ = uyvy_content[i + 1];
        *nv12_y_ptr++ = uyvy_content[i + 3];
        if (0 == i % pixels_in_a_row)
        {
            ++lines;
        }
        if (lines % 2 == 0)
        { // extract the UV value of even rows
            // copy uv channel
            *nv12_uv_ptr++ = uyvy_content[i + 2];
            *nv12_uv_ptr++ = uyvy_content[i];
        }
    }
    LOG_I("convert success");
}

void convertUYVYtoI420(char *pSrcImage, char *pDstImage, int width, int height)
{

    char *uyvy_content = pSrcImage;
    char *i420_content = pDstImage;

    char *i420_y_base = i420_content;
    char *i420_u_base = i420_y_base + width * height;
    char *i420_v_base = i420_u_base + width * height / 4;

    int y_index = 0;
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < 2 * width; j += 4)
        {
            y_index = i * 2 * width + j;
            *i420_y_base++ = uyvy_content[y_index + 1];
            *i420_y_base++ = uyvy_content[y_index + 3];
            if (i % 2)
            {
                *i420_u_base++ = uyvy_content[y_index];
                *i420_v_base++ = uyvy_content[y_index + 2];
            }
        }
    }
}

void convertNV21ToNV12(char *pSrcImage, char *pDstImage, int width, int height)
{
    // Calculate the size of a single plane in bytes
    int planeSize = width * height;

    // Copy Y plane
    memcpy(pDstImage, pSrcImage, planeSize);

    // Calculate the size of the UV plane in bytes
    int uvPlaneSize = planeSize / 2;

    // Copy and interleave UV data (U first, then V) from NV21 to NV12
    for (int i = 0; i < uvPlaneSize; i += 2)
    {
        pDstImage[planeSize + i] = pSrcImage[planeSize + i + 1]; // Copy U
        pDstImage[planeSize + i + 1] = pSrcImage[planeSize + i]; // Copy V
    }
}

void merge4NV12To1NV12(char *src1, char *src2, char *src3, char *src4, char *dst, int srcWidth, int srcHeight)
{
    int imageWidth = srcWidth;
    int imageHeight = srcHeight;
    int outputWidth = srcWidth * 2;
    int outputHeight = srcHeight * 2;
    // 拷贝第一个图像的Y分量
    for (int y = 0; y < imageHeight; y++)
    {
        for (int x = 0; x < imageWidth; x++)
        {
            dst[y * outputWidth + x] = src1[y * imageWidth + x];
        }
    }

    // 拷贝第一个图像的UV分量
    for (int y = 0; y < imageHeight / 2; y++)
    {
        for (int x = 0; x < imageWidth / 2; x++)
        {
            dst[outputWidth * outputHeight + y * outputWidth + x * 2] = src1[imageWidth * imageHeight + y * imageWidth + x * 2];
            dst[outputWidth * outputHeight + y * outputWidth + x * 2 + 1] = src1[imageWidth * imageHeight + y * imageWidth + x * 2 + 1];
        }
    }

    // 拷贝第二个图像的Y分量
    for (int y = 0; y < imageHeight; y++)
    {
        for (int x = 0; x < imageWidth; x++)
        {
            dst[y * outputWidth + x + imageWidth] = src2[y * imageWidth + x];
        }
    }

    // 拷贝第二个图像的UV分量
    for (int y = 0; y < imageHeight / 2; y++)
    {
        for (int x = 0; x < imageWidth / 2; x++)
        {
            dst[outputWidth * outputHeight + y * outputWidth + x * 2 + imageWidth] = src2[imageWidth * imageHeight + y * imageWidth + x * 2];
            dst[outputWidth * outputHeight + y * outputWidth + x * 2 + 1 + imageWidth] = src2[imageWidth * imageHeight + y * imageWidth + x * 2 + 1];
        }
    }

    // 拷贝第三个图像的Y分量
    for (int y = 0; y < imageHeight; y++)
    {
        for (int x = 0; x < imageWidth; x++)
        {
            dst[(y + imageHeight) * outputWidth + x] = src3[y * imageWidth + x];
        }
    }

    // // 拷贝第三个图像的UV分量
    for (int y = 0; y < imageHeight / 2; y++)
    {
        for (int x = 0; x < imageWidth / 2; x++)
        {

            dst[outputWidth * outputHeight + (y + imageHeight / 2) * outputWidth + x * 2] = src3[imageWidth * imageHeight + y * imageWidth + x * 2];
            dst[outputWidth * outputHeight + (y + imageHeight / 2) * outputWidth + x * 2 + 1] = src3[imageWidth * imageHeight + y * imageWidth + x * 2 + 1];
        }
    }

    // 拷贝第四个图像的Y分量
    for (int y = 0; y < imageHeight; y++)
    {
        for (int x = 0; x < imageWidth; x++)
        {
            dst[(y + imageHeight) * outputWidth + x + imageWidth] = src4[y * imageWidth + x];
        }
    }

    // 拷贝第四个图像的UV分量
    for (int y = 0; y < imageHeight / 2; y++)
    {
        for (int x = 0; x < imageWidth / 2; x++)
        {
            dst[outputWidth * outputHeight + (y + imageHeight / 2) * outputWidth + x * 2 + imageWidth] = src4[imageWidth * imageHeight + y * imageWidth + x * 2];
            dst[outputWidth * outputHeight + (y + imageHeight / 2) * outputWidth + x * 2 + 1 + imageWidth] = src4[imageWidth * imageHeight + y * imageWidth + x * 2 + 1];
        }
    }
}
void split4NV12To4NV12SideBySide(char *src, char *dst, int srcWidth, int srcHeight)
{
    int imageWidth = srcWidth;
    int imageHeight = srcHeight;
    int outputWidth = srcWidth * 2;
    int outputHeight = srcHeight * 2;

    // 拷贝Y分量 to 第一个图像
    for (int y = 0; y < imageHeight; y++)
    {
        for (int x = 0; x < imageWidth; x++)
        {
            dst[y * imageWidth + x] = src[y * outputWidth + x];
        }
    }

    // 拷贝第一个图像的UV分量
    for (int y = 0; y < imageHeight / 2; y++)
    {
        for (int x = 0; x < imageWidth / 2; x++)
        {
            dst[imageWidth * imageHeight + y * imageWidth + x * 2] = src[outputWidth * outputHeight + y * outputWidth + x * 2];
            dst[imageWidth * imageHeight + y * imageWidth + x * 2 + 1] = src[outputWidth * outputHeight + y * outputWidth + x * 2 + 1];
        }
    }

    // 拷贝第二个图像的Y分量
    for (int y = 0; y < imageHeight; y++)
    {
        for (int x = 0; x < imageWidth; x++)
        {
            dst[imageWidth * imageHeight * 3 / 2 * 1 + y * imageWidth + x] = src[y * outputWidth + x + imageWidth];
        }
    }

    // 拷贝第二个图像的UV分量
    for (int y = 0; y < imageHeight / 2; y++)
    {
        for (int x = 0; x < imageWidth / 2; x++)
        {
            dst[imageWidth * imageHeight * 3 / 2 * 1 + imageWidth * imageHeight + y * imageWidth + x * 2] = src[outputWidth * outputHeight + y * outputWidth + x * 2 + imageWidth];
            dst[imageWidth * imageHeight * 3 / 2 * 1 + imageWidth * imageHeight + y * imageWidth + x * 2 + 1] = src[outputWidth * outputHeight + y * outputWidth + x * 2 + 1 + imageWidth];
        }
    }

    // 拷贝第三个图像的Y分量
    for (int y = 0; y < imageHeight; y++)
    {
        for (int x = 0; x < imageWidth; x++)
        {
            dst[imageWidth * imageHeight * 3 / 2 * 2 + y * imageWidth + x] = src[(y + imageHeight) * outputWidth + x];
        }
    }

    // // 拷贝第三个图像的UV分量
    for (int y = 0; y < imageHeight / 2; y++)
    {
        for (int x = 0; x < imageWidth / 2; x++)
        {

            dst[imageWidth * imageHeight * 3 / 2 * 2 + imageWidth * imageHeight + y * imageWidth + x * 2] = src[outputWidth * outputHeight + (y + imageHeight / 2) * outputWidth + x * 2];
            dst[imageWidth * imageHeight * 3 / 2 * 2 + imageWidth * imageHeight + y * imageWidth + x * 2 + 1] = src[outputWidth * outputHeight + (y + imageHeight / 2) * outputWidth + x * 2 + 1];
        }
    }

    // 拷贝第四个图像的Y分量
    for (int y = 0; y < imageHeight; y++)
    {
        for (int x = 0; x < imageWidth; x++)
        {

            dst[imageWidth * imageHeight * 3 / 2 * 3 + y * imageWidth + x] = src[(y + imageHeight) * outputWidth + x + imageWidth];
        }
    }

    // 拷贝第四个图像的UV分量
    for (int y = 0; y < imageHeight / 2; y++)
    {
        for (int x = 0; x < imageWidth / 2; x++)
        {

            dst[imageWidth * imageHeight * 3 / 2 * 3 + imageWidth * imageHeight + y * imageWidth + x * 2] = src[outputWidth * outputHeight + (y + imageHeight / 2) * outputWidth + x * 2 + imageWidth];
            dst[imageWidth * imageHeight * 3 / 2 * 3 + imageWidth * imageHeight + y * imageWidth + x * 2 + 1] = src[outputWidth * outputHeight + (y + imageHeight / 2) * outputWidth + x * 2 + 1 + imageWidth];
        }
    }
}

void merge4UYVYTo1UYVY(char *src1, char *src2, char *src3, char *src4, char *dst, int srcWidth, int srcHeight)
{
    int YUYV_NUMBYTE_PER_DATA = 2;
    int WIDTH = srcWidth;
    int HEIGHT = srcHeight;
    if (src1 != nullptr && src2 != nullptr && src3 != nullptr && src4 != nullptr)
    {
        // 拼接 Y 分量和 U、V 分量（UYVY plane）
        for (int i = 0; i < HEIGHT; i++)
        {
            memcpy(dst + WIDTH * i * YUYV_NUMBYTE_PER_DATA * 2,
                   src1 + WIDTH * YUYV_NUMBYTE_PER_DATA * i, WIDTH * YUYV_NUMBYTE_PER_DATA);
            memcpy(dst + WIDTH * 2 + WIDTH * i * YUYV_NUMBYTE_PER_DATA * 2,
                   src2 + WIDTH * YUYV_NUMBYTE_PER_DATA * i, WIDTH * YUYV_NUMBYTE_PER_DATA);
            memcpy(dst + WIDTH * HEIGHT * YUYV_NUMBYTE_PER_DATA * 2 + WIDTH * i * YUYV_NUMBYTE_PER_DATA * 2,
                   src3 + WIDTH * YUYV_NUMBYTE_PER_DATA * i, WIDTH * YUYV_NUMBYTE_PER_DATA);
            memcpy(dst + WIDTH * HEIGHT * YUYV_NUMBYTE_PER_DATA * 2 + WIDTH * 2 + WIDTH * i * YUYV_NUMBYTE_PER_DATA * 2,
                   src4 + WIDTH * YUYV_NUMBYTE_PER_DATA * i, WIDTH * YUYV_NUMBYTE_PER_DATA);
        }
    }
}

void drawNV12Rectangle(char *image, int nv12_width, int nv12_height, int left, int right, int top, int bottom)
{
    int Y = 0, U = 128, V = 128;
    // 修改Y和UV平面的像素值
    for (int i = top; i < bottom; i++)
    {
        for (int j = left; j < right; j++)
        {
            int Y_offset = i * nv12_width + j;
            image[Y_offset] = Y;

            // 仅修改偶数行和列的像素值
            if (i % 2 == 0 && j % 2 == 0)
            {
                int UV_offset = nv12_width * nv12_height + (i / 2) * nv12_width + j;
                image[UV_offset] = U;
                image[UV_offset + 1] = V;
            }
        }
    }
}
void drawUYVYRectangle(char *image, int uyvy_width, int uyvy_height, int left, int right, int top, int bottom)
{
    int Y = 0, U = 128, V = 128;
    // 计算矩形的边界

    for (int i = top; i < bottom; i++)
    {
        for (int j = left; j < right; j++)
        {
            int pixelIndex = (i * uyvy_width + j) * 2 - 1;
            // 修改UY分量，使像素呈现某种颜色
            image[pixelIndex] = Y;
            if (1 == pixelIndex % 4)
            {
                image[pixelIndex - 1] = U; // U分量置为0
                image[pixelIndex + 1] = V; // Y2分量置为0
            }
        }
    }
}

int64_t get_milliseconds()
{
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ((int64_t)ts.tv_sec) * 1000 + ((int64_t)ts.tv_nsec) / 1000000;
}

int LoadImg(const char *inputFile, char *data, int size)
{
    FILE *file = fopen(inputFile, "rb");
    if (file == NULL)
    {
        LOG_E("file is NULL");
        return -1;
    }
    fread(data, 1, size, file);
    fclose(file);
    LOG_D("loadimg success");
    return 0;
}

const char *yuvFormatToString(YuvFormat format)
{
    switch (format)
    {
    case I420:
        return "I420";
    case NV12:
        return "NV12";
    case NV21:
        return "NV21";
    case YV12:
        return "YV12";
    case RGB:
        return "RGB";
    case UYVY:
        return "UYVY";
    default:
        return "UNKNOWN";
    }
}

int yuvImageSize(int width, int height, YuvFormat format)
{
    int imageSize = 0;
    switch (format)
    {
    case UYVY:
        imageSize = width * height * 2;
        break;
    case I420:
    case YV12:
    case NV12:
    case NV21:
        imageSize = width * height * 3 / 2;
        break;
    case RGB:
        imageSize = width * height * 3;
        break;
    default:
        LOG_E("UNKNOWN Format!");
    }
    return imageSize;
}

int saveYUV(char *data, int width, int height, YuvFormat format)
{
    char filename[128];
    int size = 0;
    sprintf(filename, "../resources/dump_%d_%d.%s", width, height, yuvFormatToString(format));

    size = yuvImageSize(width, height, format);
    FILE *fp = fopen(filename, "w+");
    int ret = 0;
    if (fp)
    {
        ret = fwrite(data, sizeof(char), size, fp);
        if (ret < 0)
            fclose(fp);
    }
    LOG_I("save %s success", filename);
    return 0;
}

// c pthread
pthread_mutex_t mutex;
pthread_cond_t cond;
int ready = 0; // 标志，指示条件是否满足
void *thread1(void *arg)
{
    printf("Thread 1: Waiting for signal...\n");

    pthread_mutex_lock(&mutex);
    while (ready == 0)
    {
        pthread_cond_wait(&cond, &mutex);
    }
    printf("Thread 1: Received signal, proceeding...\n");
    pthread_mutex_unlock(&mutex);

    pthread_exit(NULL);
}

void *thread2(void *arg)
{
    printf("Thread 2: Sleeping for 2 seconds...\n");
    usleep(2 * 1000); // 模拟一些处理时间

    pthread_mutex_lock(&mutex);
    ready = 1;
    pthread_cond_signal(&cond);
    printf("Thread 2: Sent signal.\n");
    pthread_mutex_unlock(&mutex);

    pthread_exit(NULL);
}
void testPthread()
{
    pthread_t t1, t2;

    // 初始化互斥锁和条件变量
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);

    // 创建线程
    pthread_create(&t1, NULL, thread1, NULL);
    pthread_create(&t2, NULL, thread2, NULL);

    // 等待线程完成
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    // 销毁互斥锁和条件变量
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
}

// c input output
void testPutchar()
{
    // 场景：逐个字符输出的情况，比如处理单个字符的输出或调试时输出字符。
    // 适用情况：简单的字符输出，不需要格式化，通常用于调试或简单的字符显示。
    char c = 'A';
    putchar(c);
    putchar('\n');
}

void testGetchar()
{
    // 场景：逐个字符输入的情况，比如处理单个字符的输入或需要从用户那里获取单个字符。
    // 适用情况：需要从用户输入读取单个字符，比如处理命令行输入或字符流。
    int c;
    printf("Enter a character: ");
    c = getchar();
    printf("You entered: ");
    putchar(c);
    putchar('\n');
}

void testPrintf()
{
    // 场景：需要格式化输出的情况，比如打印变量的值、格式化输出复杂的字符串信息等。
    // 适用情况：几乎所有需要格式化输出的情况，特别是当需要输出多个变量或格式化数据时。
    int age = 25;
    float height = 5.9;
    printf("I am %d years old and %.1f feet tall.\n", age, height);
}

void testScanf()
{
    // 场景：需要格式化输入的情况，比如从标准输入读取多个变量。
    //  适用情况：从用户输入中读取格式化的数据，比如读取整型、浮点型或字符串。
    int age;
    float height;
    printf("Enter your age and height: ");
    scanf("%d %f", &age, &height);
    printf("You are %d years old and %.1f feet tall.\n", age, height);
}

void testFgets()
{
    // 场景:安全地从标准输入读取一行字符串，防止缓冲区溢出。
    // 适用情况：需要从输入中读取字符串时使用，更安全，适用于任何读取字符串的场景。
    char str[100];
    printf("Enter a string: ");
    fgets(str, sizeof(str), stdin);
    printf("You entered: %s", str);
}

void testPuts()
{
    //     场景：

    // 输出一个字符串，并在结尾添加换行符。
    // 适用情况：简单的字符串输出，自动添加换行符。
    char str[] = "Hello, World!";
    puts(str);
}

void testSprintf()
{
    //  场景：
    // 将格式化数据写入字符串中。
    // 适用情况：需要将格式化数据保存到字符串中，适用于生成包含格式化数据的字符串。
    char buffer[100];
    int age = 25;
    float height = 5.9;
    sprintf(buffer, "I am %d years old and %.1f feet tall.", age, height);
    printf("%s\n", buffer);
}

void testSnprintf()
{
    // 场景：
    // 将格式化数据写入指定长度的字符串中，防止缓冲区溢出。
    // 适用情况：类似于 sprintf，但更安全，适用于需要防止缓冲区溢出的情况。
    char buffer[20];
    int age = 25;
    float height = 5.9;
    snprintf(buffer, sizeof(buffer), "I am %d years old and %.1f feet tall.", age, height);
    printf("%s\n", buffer);
}

void testSscanf()
{
    // 场景：
    // 从字符串中读取格式化数据。
    // 适用情况：需要从字符串中解析格式化数据时使用，比如从包含数据的字符串中提取信息。
    char str[] = "25 5.9";
    int age;
    float height;
    sscanf(str, "%d %f", &age, &height);
    printf("You are %d years old and %.1f feet tall.\n", age, height);
}

void reverseString(char *src)
{
    char *start = src;
    char *end = src + strlen(src) - 1;
    char temp;

    while (start < end)
    {

        temp = *start;
        *start = *end;
        *end = temp;
        start++;
        end--;
    }
}
